package info.himanshug.www.imageprocessing;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.util.Log;

public class ColorDodgeComposite {

	private float alpha = 1.0f;
	
	public ColorDodgeComposite(float alpha) {
		this.alpha = alpha;
	}
	
	public Bitmap compose(Bitmap in1, Bitmap in2) {
		return compose(in1,in2,null);
	}
	
	//TODO: assumes both images are of exactly same dimension
    public Bitmap compose(Bitmap in1, Bitmap in2, Bitmap dst) {

    	int in1W = in1.getWidth();
    	int in2W = in2.getWidth();
    	int in1H = in1.getHeight();
    	int in2H = in2.getHeight();
    	
        int[] srcPix = new int[in1W * in1H];
        int[] dstPix = new int[in2W * in2H];
        in1.getPixels(srcPix, 0, in1W, 0, 0, in1W, in1H);
        in2.getPixels(dstPix, 0, in1W, 0, 0, in1W, in1H);
    	
        int total = srcPix.length;
        for(int i = 0; i < total; i++) {
        	dstPix[i] = blend_dodge(srcPix[i],dstPix[i]);
        }
        
        if(dst == null)
        	dst = in2.createBitmap(in1W, in1H, Config.ARGB_8888);
        
        dst.setPixels(dstPix, 0, in2W, 0, 0, in2W, in2H);
        return dst;
        
//        int x = 0;
//        int w = in1.getWidth();
//        int y0 = 0;
//        int y1 = y0 + in1.getHeight();
//        
//    	
//
//    	Bitmap dstOut = in1.copy(Config.ARGB_8888, true);
//    	Log.i("FOTOFUN","in = " + in1.getWidth());
//    	Log.i("FOTOFUN","w = " + dstOut.getWidth());
//    	
//    	Log.i("FOTOFUN","inH = " + in1.getHeight());
//    	Log.i("FOTOFUN","h = " + dstOut.getHeight());
//    	int[] srcPix = new int[dstOut.getWidth() * 1];
//    	int[] dstPix = new int[dstOut.getWidth() * 1];
//    	
//    	
//        for ( int y = y0; y < y1; y++ ) {
//            in1.getPixels(srcPix, 0, w, x, y, w, 1);
//            in2.getPixels(dstPix, 0, w, x, y, w, 1);
//            //dstPix = dstIn.getPixels( x, y, w, 1, dstPix );
//            composeRGB( srcPix, dstPix, alpha );
//            //dstOut.setPixels( x, y, w, 1, dstPix );
//            dstOut.setPixels(dstPix, 0, w, x, y, w, 1);
//        }
//        
//        //in2.setPixels(dstPix, 0, in2W, 0, 0, in2W, in2H);
//		return dstOut;
    	
    }
    
    public static final int ALPHA_MASK = 0xff000000;
    public static final int RED_MASK   = 0x00ff0000;
    public static final int GREEN_MASK = 0x0000ff00;
    public static final int BLUE_MASK  = 0x000000ff;
    
    private static int blend_dodge(int a, int b) {
        // setup (this portion will always be the same)
        int f = (b & ALPHA_MASK) >>> 24;
        int ar = (a & RED_MASK) >> 16;
        int ag = (a & GREEN_MASK) >> 8;
        int ab = (a & BLUE_MASK);
        int br = (b & RED_MASK) >> 16;
        int bg = (b & GREEN_MASK) >> 8;
        int bb = (b & BLUE_MASK);
        // formula:
        int cr = (br==255) ? 255 : peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing
        int cg = (bg==255) ? 255 : peg((ag << 8) / (255 - bg)); // "
        int cb = (bb==255) ? 255 : peg((ab << 8) / (255 - bb)); // "
        // alpha blend (this portion will always be the same)
        return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
                (peg(ar + (((cr - ar) * f) >> 8)) << 16) |
                (peg(ag + (((cg - ag) * f) >> 8)) << 8) |
                (peg(ab + (((cb - ab) * f) >> 8)) ) );
      }
    
    private static int low(int a, int b) {
        return (a < b) ? a : b;
      }
    private static int peg(int n) {
        return (n < 0) ? 0 : ((n > 255) ? 255 : n);
      }
    public void composeRGB( int[] src, int[] dst, float alpha ) {
        int w = src.length;

        for ( int i = 0; i < w-3; i += 4 ) {
            int sr = src[i];
            int dir = dst[i];
            int sg = src[i+1];
            int dig = dst[i+1];
            int sb = src[i+2];
            int dib = dst[i+2];
            int sa = src[i+3];
            int dia = dst[i+3];
            int dor, dog, dob;

            if (sr != 255)
                dor = Math.min((dir << 8) / (255-sr), 255);
            else
                dor = sr;
            if (sg != 255)
                dog = Math.min((dig << 8) / (255-sg), 255);
            else
                dog = sg;
            if (sb != 255)
                dob = Math.min((dib << 8) / (255-sb), 255);
            else
                dob = sb;

            float a = alpha*sa/255f;
            float ac = 1-a;

            dst[i] = (int)(a*dor + ac*dir);
            dst[i+1] = (int)(a*dog + ac*dig);
            dst[i+2] = (int)(a*dob + ac*dib);
            dst[i+3] = (int)(sa*alpha + dia*ac);
        }
    }
}
